import java.awt.Point;
import java.awt.Rectangle;
import java.util.*; 
import java.awt.*;
import java.util.HashMap;
import java.io.*;

public class Card {
	
	private boolean hasTable = false;
	private Table table = null;
	
	private Image pic;
	private Image back;
	private boolean init;
	
	private int CardID;
	private int immutableID;
	private Rectangle cardRec = new Rectangle(72,96);
	private Point location = new Point();
	private int z;
	private boolean faceUp = false;
	private boolean flipable = true;
	private boolean moveable = true;
	private String name;
	private HashMap<String, String> attributes;
	
	private static int nextZ;
	
	private static int highestID = 0;
	
	public Card(int ID) {
		setID(ID);
		immutableID = ID;
		z = nextZ;
		nextZ += 1;
		init = false;
	}
	
	
	public Card(int ID, String img, String b) {
		this(ID);
		pic = Toolkit.getDefaultToolkit().getImage(img);
		back = Toolkit.getDefaultToolkit().getImage(b);
		init = true;
	}
	
	public Card(int ID, String img, String b, String name) {
		this(ID,img,b);
		this.name = name;
	}
	
	public void setTable(Table t) {
		hasTable = (t!=null);
		table = t;
	}
	
	public void addAttribute(String key, String value) {
		if(attributes == null) {attributes = new HashMap<String, String>();}
		attributes.put(key, value);
	}
	
	public String getAttribute(String key) {
		return attributes.get(key);
	}
	
	public void setImages(String img, String b){
		pic = Toolkit.getDefaultToolkit().getImage(img);
		back = Toolkit.getDefaultToolkit().getImage(b);
		init = true;
	}
	
	/**
	Assigns this card a new ID that is guaranteed not to be used by any other cards.
	*/
	public void autoAssignID() {
		setID(highestID+1);
	}
	
	public void setID(int ID) {
		CardID = ID;
		highestID = (int)Math.max(highestID,CardID);
	}
	
	public int getID() {
		return CardID;
	}
	
	public int getImmutableID() {
		return immutableID;
	}
	
	public Rectangle getRectangle() {
		return cardRec;
	}
	
	public Point getLocation() {
		location.setLocation(cardRec.getX(), cardRec.getY());
		return location;
	}

	public void setRectangle(Rectangle cardRec) {
		this.cardRec = cardRec;
	}
	
	public void setSize(int x, int y) {
		 cardRec.setSize(x, y);
		
	}
	
	/**
	 * Sets the location of the card.
	 * 
	 * @return true if the card was successfully moved, false otherwise.
	 * */
	public boolean setLocation(Point location) {
		if(moveable) {
			Rectangle newpos = new Rectangle(cardRec);
			newpos.setLocation(location);
			if (!hasTable || table.isInBounds(newpos)) {
				cardRec = newpos;
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Sets the location of the card.
	 * 
	 * @return true if the card was successfully moved, false otherwise.
	 * */
	public boolean setLocation(int x, int y) {
		return setLocation(new Point(x,y));
	}
	
	public int getZ() {
		return z;
	}

	public void setZ(int z) {
		this.z = z;
	}
	
	public void setFaceUp(boolean f) {
		if(flipable) {
			faceUp = f;
		}
	}
	
	public void setFaceUp() {
		if(flipable) {
			faceUp = true;
		}
	}
	
	public void setFaceDown() {
		if(flipable) {
			faceUp = false;
		}
	}
	
	public void toggleFaceUp() {
		if(flipable) {
			faceUp = !faceUp;
		}
	}
	
	public boolean isFaceUp() {
		return faceUp;
	}
	
	public boolean isFlipable() {
		return flipable;
	}
	
	public void setFlipable(boolean flip) {
		flipable = flip;
	}
	
	public boolean isMoveable() {
		return moveable;
	}
	
	public void setMoveable(boolean move) {
		moveable = move;
	}
	
	public Image getImage(){
		if(!init){
			return null;
		}
		
		if(faceUp){
			return pic;
		}
		return back;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public String toString() {
		return getName();
	}
	
	public int hashCode() {
		return getID();
	}
	
	public boolean equals(Object o) {
		try {
			Card other = (Card)o;
			return other.getID()==this.getID();
		} catch (ClassCastException e) {
			return false;
		}
	}
	
	public boolean overlaps(Card othercard) {
		return this.getRectangle().intersects(othercard.getRectangle());
	}
	
	
	public CardData getCardData() {
		return new CardData(immutableID, getLocation(), getZ(), isFaceUp());
	}
	
	public void setCardData(CardData cd) {
		setLocation(cd.p);
		setZ(cd.z);
		//nextZ = z+1;
		setFaceUp(cd.f);
	}
	
	
	public boolean moveBy (Point point) {
		return setLocation(getLocation().x + point.x, getLocation().y + point.y);
	}
	
	public boolean moveBy (int x, int y) {
		return setLocation(getLocation().x + x, getLocation().y + y);
	}
	
}
